package com.lcc.lynx.eps;

import com.lcc.lynx.common.utils.FileUtils;
import com.lcc.lynx.common.utils.JsonUtil;
import com.lcc.lynx.common.utils.StrUtil;
import com.lcc.lynx.jdbc.IBaseController;
import com.lcc.lynx.jdbc.IByIdController;
import jakarta.annotation.PostConstruct;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.*;

/**
 * 实体信息与路径
 */
@Getter
@Slf4j
@Component
@Order
@RequiredArgsConstructor
public class CoolEps {

//    @Value("${server.servlet.context-path}")
    private String contextPath = "";

    final private EpsProperties epsProperties;

    final private RequestMappingHandlerMapping requestMappingHandlerMapping;

    Map<String, CtlVO> admin = new HashMap<>();

    @PostConstruct
    public void init() {
        if(epsProperties.getVueApiPath() == null){
            return;
        }
        Runnable task = () -> {
//            entity();
            urls();
            log.info("[lynx] =================== eps Api接口生成完成 ===================");
        };
        // ThreadUtil.safeSleep(3000);
        task.run();
    }



    /**
     * 构建所有的url
     */
    private void urls() {
        List<String> baseApis = Arrays.asList("info", "list", "update", "insert", "delete", "page", "insertList", "save");
        Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
        Set<String> set = new HashSet<>();
        // 过滤排除com.lcc包以外的
        for1: for (Map.Entry<RequestMappingInfo, HandlerMethod> methodEntry : map.entrySet()) {
            if(!methodEntry.getValue().getBeanType().getName().startsWith("com.lcc")){
                continue ;
            }
            RequestMappingInfo info = methodEntry.getKey();
            HandlerMethod method = methodEntry.getValue();
            Iterator<String> iterator = info.getDirectPaths().iterator();
            if(!iterator.hasNext()){
                continue;
            }
            String uri = info.getDirectPaths().iterator().next();
            String controller = method.getBeanType().getSimpleName();
            String methodName = method.getMethod().getName();
            String uri0 = getControllerRequestMappingValue1(method.getBeanType());
            set.add(controller);
            admin.computeIfAbsent(controller,
                    k -> new CtlVO(method.getBeanType(), contextPath + uri0));
            for (String baseApi : baseApis) {
                if((uri0 + "/" + baseApi).equals(uri) && ifBaseApi(method)){
                    continue for1;
                }
            }

            ApiVO api = new ApiVO();
            api.setName(methodName);
            api.setUri(contextPath + uri);
            api.setContentType(getContentType(method));
            api.setMethod(getMethodType(method));
            admin.get(controller).getApis().add(api);
        }
        List<String> controllers = new ArrayList<>(set);
        controllers.sort(Comparator.naturalOrder());
        Map<String, CtlVO> admin2 = admin;
        admin = new LinkedHashMap<>();
        for (String controller : controllers) {
            admin.put(controller, admin2.get(controller));
        }

        // 给apis排序
        for (CtlVO ctlVO : admin.values()) {
            ctlVO.getApis().sort(Comparator.comparing(ApiVO::getName));
        }
//        自动生成前端Api接口
        createApiTypeTs();
    }

    private boolean ifBaseApi(HandlerMethod method) {
        for (Class<?> anInterface : method.getBeanType().getInterfaces()) {
            if (anInterface.equals(IBaseController.class) || anInterface.equals(IByIdController.class)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获得方法的url地址
     *
     * @param handlerMethod 方法
     * @return 方法url地址
     */
    private String getContentType(HandlerMethod handlerMethod) {
        Method method = handlerMethod.getMethod();
        // 判断 方法 参数中的注解 是否包含requestBody注解
        if (method.getParameterCount() > 0) {

            for (Parameter parameter : method.getParameters()) {
                Annotation[] annotations = parameter.getAnnotations();
                for (Annotation annotation : annotations) {
                    if (annotation.annotationType().equals(RequestBody.class)) {
                        return "json";
                    }
                    if (annotation.annotationType().equals(PathVariable.class)){
                        return "path";
                    }
                }
                // 判断是否是MultipartFile
                if (parameter.getType().equals(MultipartFile.class)) {
                    return "form-data";
                }
            }
        }
        if (method.isAnnotationPresent(GetMapping.class)) {
            return "get";
        }
        return "url";
    }

    /**
     * 判断请求方式
     * @param handlerMethod
     * @return
     */
    private String getMethodType(HandlerMethod handlerMethod) {
        Method method = handlerMethod.getMethod();

        // 判断方法是否被getRequestMapping注解修饰
        if (method.isAnnotationPresent(GetMapping.class)) {
            return "get";
        }

        return "post";
    }
    private String getControllerRequestMappingValue1(Class clazz) {
        RequestMapping requestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
        if (requestMapping != null && requestMapping.value().length > 0) {
            return requestMapping.value()[0];
        }
        return "";
    }

    private void createApiTypeTs(){
        StringBuilder sb = new StringBuilder("""
            import { IByIdController, IBaseController, RespType } from "./api"
            
            export interface Api {
            """);
        for (String key : admin.keySet()) {
            CtlVO ctlVO = admin.get(key);
            sb.append("    ").append(ctlVO.getKeyName()).append(": ");
            if(ctlVO.getApis().isEmpty()){
                sb.append(ctlVO.getImplementName()==null?"any":ctlVO.getImplementName());
            }else{
                sb.append(key).append("Api");
            }
            sb.append("\n");
        }
        sb.append("}\n");
        for (String key : admin.keySet()) {
            CtlVO ctlVO = admin.get(key);
            if(ctlVO.getApis().isEmpty()){
                continue;
            }
            sb.append("interface ").append(key).append("Api");
            if(StrUtil.isNotEmpty(ctlVO.getImplementName())){
                sb.append(" extends ").append(ctlVO.getImplementName());
            }
            sb.append(" {\n");
            for (ApiVO api : ctlVO.getApis()) {
                sb.append("    ").append(api.getName()).append(": (data?: any) => Promise<RespType>\n");
            }
            sb.append("}\n");
        }
        File file = new File(epsProperties.getVueApiPath());
        FileUtils.write(new File(file, "ApiType.ts"), sb.toString());

        FileUtils.write(new File(file,"api.json"), JsonUtil.toJSONString(admin));

    }



}
